import type { App } from '@vue/runtime-core'
import type { ReturnType } from 'birpc'
import type { InjectionKey } from 'vue'
import { inject } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
import { useMetaStore } from '~/store/meta'
import { isDesktopUa, isIos, roundToTwoDecimalPlaces, useAsset, useSvg } from '~/utils'

const CommonPluginKey: InjectionKey<OpenApiType> = 'CommonPluginKey' as unknown as Symbol

export type OpenApiType = ReturnType<typeof getOpenApi>
declare module '@vue/runtime-core' {
  export interface ComponentCustomProperties extends OpenApiType {}
}

const getOpenApi = (vueApp: App<any>) => {
  const publicConfig = useRuntimeConfig().public
  const router = useRouter()
  const metaStore = useMetaStore()
  const localeRoute = useLocaleRoute()
  const localePath = useLocalePath()
  const i18n = vueApp.$nuxt.$i18n
  const { curCurrency } = storeToRefs(metaStore)
  const headers = useRequestHeaders(['User-Agent'])
  const isLargeScreenInClient = useMediaQuery('(min-width: 1024px)')
  const isLargeScreenInEveryWhere = computed(() => {
    if (process.client) return isLargeScreenInClient.value
    const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(headers['user-agent'])
    return !isMobile
  })
  return {
    useAsset,
    useSvg,
    handleContact() {
      open(
        `https://go.crisp.chat/chat/embed/?website_id=${window.CRISP_WEBSITE_ID}&token_id=${window.CRISP_TOKEN_ID}`,
        '__blank',
      )
    },
    miniProgramPay({ prepayId, merchantId, totalFee, currency, merchantTradeNo } = {} as any) {
      if (isIos()) {
        const params = {
          merchantId: String(merchantId),
          merchantTradeNo: String(merchantTradeNo),
          prepayId: String(prepayId),
          totalFee: String(totalFee),
          currency,
        }
        return window.webkit.messageHandlers.gatepay.postMessage(params)
      }
      return window.gateio.gatepay(merchantId, merchantTradeNo, prepayId, totalFee, currency)
    },
    $mt(key) {
      const { t, locale } = i18n as any
      if (locale.value === 'en') return key
      return t(key.replace('@', `{'@'}`))
    },
    gtag_report(eventName) {
      if (!window.zaraz) return
      zaraz.track(eventName)
    },
    async gtag_report_conversion() {
      if (!window.zaraz) return
      return new Promise(async (resolve) => {
        await zaraz.track('conversion', {
          send_to: 'AW-10931301268/rQSWCMHB14cZEJTXudwo',
        })
        resolve(1)
      })
    },
    $multiplyWithRate(price, offRate) {
      if (!offRate) offRate = 0
      const rate = (+offRate + 100) / 100
      return price * rate
    },
    getCurrentLangCode(route) {
      const langCode = route.path.split('/')[1]
      const LANGUAGES = publicConfig.LANGUAGES as any[]
      const isHitLang = LANGUAGES.some(({ code }) => code === langCode)
      if (!isHitLang) return 'en'
      return langCode
    },
    $localePath(route, code?) {
      if (!route) return route
      if (typeof route === 'object') return localeRoute(route, code).fullPath
      if (route.startsWith('http')) return route
      if (route.endsWith('.html')) return route
      return localePath(route, code)
    },

    hasToken() {
      return process.client && localStorage.getItem('authToken')
    },
    $getExchangePrice(num: number) {
      if (isNaN(num)) num = 0
      if (!curCurrency.value.exchangeRate) return num
      const { exchangeRate, symbol, name } = curCurrency.value
      return +roundToTwoDecimalPlaces(+num * exchangeRate)
    },
    $withCurrencySymbol(num: number) {
      const { exchangeRate, symbol, name } = curCurrency.value
      return `${symbol} ${roundToTwoDecimalPlaces(num).toFixed(2)}`
    },
    $calcPrice(num: number) {
      if (isNaN(num)) num = 0
      if (!curCurrency.value.exchangeRate) return `USD ${(+roundToTwoDecimalPlaces(+num)).toFixed(2)}`
      const { exchangeRate, symbol, name } = curCurrency.value
      num = +num * +exchangeRate
      return `${symbol} ${(+roundToTwoDecimalPlaces(num)).toFixed(2)}`
    },
    $calcDiscount(num: number = 0) {
      if (!num) return num
      return `${num.toFixed(1)}% off`
    },
    $payWithOrderInfo({
      orderInfo = {},
      showReport,
      showQRCode,
      paymentData = {},
    }: {
      orderInfo: any
      showReport: boolean
      showQRCode?: boolean
      paymentData: any
    }) {
      const { paymentCode, isShowQrCodePC: isNeedShowQrCode } = paymentData
      let { pcPayPath, jsonPath } = orderInfo?.paymentParamsData || {}
      if (!pcPayPath) return this.$pushRoute('/user/order')
      showLoadingToast({ message: this.$mt('Heading to the checkout'), duration: 3000 })
      if (isNeedShowQrCode && isDesktopUa() && showQRCode) return { type: 'SHOW_QR_CODE', pcPayPath }
      const payWithBiance = () => {
        if (paymentCode !== 'BINANCE_PAY') return
        try {
          const { appUrl, checkoutUrl } = JSON.parse(jsonPath)
          // 先打开web支付页面 然后走下面的跳转app页面 这样App没打开也有个web页面保底
          pcPayPath = checkoutUrl
          location.href = appUrl
        } catch (e) {
          console.log(e)
        }
      }
      if (showReport) {
        return Promise.race([this.gtag_report_conversion(), new Promise((resolve) => setTimeout(resolve, 1000))]).then(
          () => {
            payWithBiance()
            return (location.href = pcPayPath)
          },
        )
      }
      payWithBiance()
      return (location.href = pcPayPath)
    },

    $getDiscountMoneyOff(totalAmount: number, rate: number = 0) {
      return ((100 + (rate || 0)) / 100) * totalAmount
    },
    $pushRoute(route: RouteLocationRaw | string) {
      return (location.href = this.$localePath(route))
    },
    $softRoute(route: RouteLocationRaw | string) {
      return router.push(this.$localePath(route))
    },
    $softReplaceRoute(route: RouteLocationRaw | string) {
      return router.replace(this.$localePath(route))
    },
    $forcePushRoute(path: string) {
      return (location.href = path)
    },
    $forceReplaceRoute(path: string) {
      return location.replace(path)
    },
    $replaceRoute(route: RouteLocationRaw | string) {
      return router.replace(route)
    },
    $popRoute() {
      return router.back()
    },
    $withPicOrigin(url: string) {
      return url
    },
    $isPcScreen() {
      return isLargeScreenInEveryWhere.value
    },

    $reloadPage() {
      location.reload()
    },
  }
}

export function CommonPlugin(app: App<any>) {
  const apis = getOpenApi(app)
  Object.assign(app.config.globalProperties, apis)
  app.provide(CommonPluginKey, apis)
}

export function useCommonPlugin() {
  const api = inject(CommonPluginKey)
  //   将api的函数全绑定到api上
  return new Proxy(api, {
    get(target, key) {
      if (typeof target[key] !== 'function') return target[key]
      return target[key].bind(target)
    },
  })
}
